﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGourd.Core.Runners;
using NGourd.Core.Reports;
using NGourd.Core.Exceptions;

namespace NGourd.Core.Plans
{
    class PlanBuilder
    {
        private readonly StepLibrary stepLibrary;

        public PlanBuilder(StepLibrary stepLibrary)
        {
            this.stepLibrary = stepLibrary;
        }

        public IPlan FormulatePlanForFeatureSet(params NGourd.Core.Features.Feature[] features)
        {
            var plan = new MultiStepPlan("Feature Set", ReportTarget.FEATURE_SET);
            plan.AddStep(new BeforeAllScenarioStep(stepLibrary));
            foreach (var feature in features)
            {
                plan.AddStep(FormulatePlanForFeature(feature));
            }
            plan.AddStep(new AfterAllScenarioStep(stepLibrary));
            return plan;
        }

        IPlan FormulatePlanForFeature(NGourd.Core.Features.Feature feature)
        {
            var plan = new MultiStepPlan(feature.Name, ReportTarget.FEATURE);
            foreach (var scenario in feature.Scenarios)
            {
                plan.AddStep(FormulatePlanForScenario(scenario));
            }
            return plan;
        }

        IPlan FormulatePlanForScenario(NGourd.Core.Features.Scenario scenario)
        {
            var plan = new MultiStepPlan(scenario.Name, ReportTarget.SCENARIO);
            plan.AddStep(new BeforeScenarioStep(stepLibrary));
            bool skipping = false;
            foreach (var step in scenario.AllSteps)
            {
                var planStep = FormulatePlanForStep(step);
                if (!skipping)
                    plan.AddStep(planStep);
                else
                    plan.AddStep(new SkipPlanStep(ReportTarget.SCENARIO, ReportStatus.SKIPPED, step.Text, "Previous Step not run"));

                // HACK: YUCK!
                //skipping = planStep is SkipPlanStep;
            }
            plan.AddStep(new AfterScenarioStep(stepLibrary));

            return plan;
        }

        IPlan FormulatePlanForStep(NGourd.Core.Features.Step step)
        {
            try
            {
                var execStep = stepLibrary.GetStepForText(step.Text);
                if (execStep == null)
                    return new SkipPlanStep(ReportTarget.STEP, ReportStatus.INCONCLUSIVE, step.Text, "No steps found");
                return new ExecutePlanStep(execStep, step.Text);
            }
            catch (AmbiguousStepException asex)
            {
                return new SkipPlanStep(ReportTarget.STEP, ReportStatus.SKIPPED, step.Text, asex.ToString());
            }
            catch (Exception ex)
            {
                return new SkipPlanStep(ReportTarget.STEP, ReportStatus.SKIPPED, step.Text, ex.ToString());
            }
        }
    }
}
